﻿using Mozi.HttpEmbedded;
using Mozi.HttpEmbedded.Extension;
using Mozi.Live.RTP;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Mozi.Live
{
    //TODO 定时移除会话

    /// <summary>
    /// 会话管理器
    /// </summary>
    public class SessionManager
    {
        private List<Session> _sessions = new List<Session>();
        
        public List<Session> GetAll()
        {
            return _sessions;
        }
        /// <summary>
        /// 增加
        /// </summary>
        /// <param name="se"></param>
        public void Add(Session se)
        {
            _sessions.Add(se);
        }
        /// <summary>
        /// 移除
        /// </summary>
        /// <param name="se"></param>
        public void Remove(Session se)
        {
            //清空缓存
            se.ClearBuffer();
            _sessions.Remove(se);
        }
        /// <summary>
        /// 移除
        /// </summary>
        /// <param name="id"></param>
        public void Remove(string id)
        {
            Session se = Find(id);
            if (se != null)
            {
                _sessions.Remove(se);
            }
        }
        /// <summary>
        /// 查找指定的会话
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Session Find(string id)
        {
            return _sessions.Find(x => x.Id == id&&!string.IsNullOrEmpty(id));
        }

        public Session FindByAddress(string host)
        {
            return _sessions.Find(x => x.ClientAddress == host);
        }
        public Session FindPublisher(string resourceName)
        {
            return _sessions.Find(x => resourceName == x.ResourceName);
        }
        public List<Session> GetSubscribers()
        {
            return _sessions.FindAll(x => !x.IsPublisher);
        }
        public List<Session> GetSubscribers(string resourceName)
        {
            return _sessions.FindAll(x => !x.IsPublisher&&Equals(x.ResourceName,resourceName));
        }
        /// <summary>
        /// 设置会话状态
        /// </summary>
        /// <param name="id"></param>
        /// <param name="state"></param>
        public void SetSessionState(string id,SessionState state)
        {
            Session session = Find(id);
            if (session != null)
            {
                session.State = state;
            }
        }
    }
    /// <summary>
    /// 会话管理
    /// </summary>
    public class Session
    {
        /// <summary>
        /// 会话编号
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// 资源名称 发布|请求
        /// </summary>
        public string ResourceName { get; set; }
        /// <summary>
        /// 会话超时时间
        /// </summary>
        public int Timeout { get; set; }
        /// <summary>
        /// 地址类型
        /// </summary>
        public string AddressType { get; set; }
        /// <summary>
        /// TCP|UDP
        /// </summary>
        public ProtocolVersion TransferProtocol { get; set; }
        /// <summary>
        /// 通讯协商地址
        /// </summary>
        public List<TransportInfo> Transports { get; set; }
        /// <summary>
        /// 会话状态
        /// </summary>
        public SessionState State { get; set; }
        /// <summary>
        /// 会话渠道
        /// </summary>
        public Socket Pipe { get; set; }
        /// <summary>
        /// 会话创建时间
        /// </summary>
        public DateTime CreateTime { get; set; }
        /// <summary>
        /// 客户机地址，此处仅用来关联客户机的RTSP会话地址，并不表示客户机的RTP|RTCP通讯地址。RTP通讯地址请使用<see cref="TransportInfo.ClientAddress"/>
        /// </summary>
        public string ClientAddress { get; set; }
        /// <summary>
        /// 是否是发布源
        /// </summary>
        public bool IsPublisher { get; set; }

        //视频缓存
        private RTPBuffer _buffer0 = new RTPBuffer();
        //音频缓存
        private RTPBuffer _buffer1 = new RTPBuffer();

        private Timer _timer;
        private int sendInterval = 30;

        public RTPMessageTransmitMix MessageSendRTP;
        public RTCPMessageTransmitMix MessageSendRTCP;

        /// <summary>
        /// 
        /// </summary>
        public Session()
        {
            CreateTime = DateTime.Now;
            Transports = new List<TransportInfo>();
            _timer = new Timer(SendPack, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
        }
        public void Push(byte channel, RTPPackage pack)
        {
            if (channel == 0)
            {
                _buffer0.Push(pack);
                Pipe.Send(PackMixedRTP(0, pack.Pack()));
            }
            else if (channel == 2)
            {
                _buffer1.Push(pack);
                Pipe.Send(PackMixedRTP(2, pack.Pack()));
            }
        }
        public bool Play()
        {
            State = SessionState.Play;
            _timer.Change(0, sendInterval);
            return false;
        }

        public void SendPack(object state)
        {
            _timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            //try
            //{
            //    if (RTSP.RTSPTransportProtocol.IsTCP(TransferProtocol))
            //    {
                     
            //        if (!_buffer0.IsEmpty && Pipe.Connected)
            //        {
            //            //先发送SR
            //            RTCPSenderPackage rr = new RTCPSenderPackage();
            //            rr.SendTime = DateTime.UtcNow;
            //            rr.Timestamp = _buffer0.Packages[0].Timestamp;
            //            rr.Identifier = _buffer0.Packages[0].SSRC;
            //            //rr.PacketCount = (uint)_buffer0.Packages.Count(x => x != null);
            //            //rr.PayloadLength = (uint)_buffer0.Packages.Where(x => x != null).Sum(x => x.Length);

            //            byte chRTCP = 0 + 1;
            //            byte chRTP = 0;

            //            //Pipe.Send(PackMixedRTP(chRTCP, rr.Pack()));

            //            if (MessageSendRTCP != null)
            //            {
            //                MessageSendRTCP(((IPEndPoint)Pipe.RemoteEndPoint).Address.ToString(), ((IPEndPoint)Pipe.RemoteEndPoint).Port, "TCP", chRTCP, rr);
            //            }

            //            foreach (var p in _buffer0.Packages)
            //            {
            //                Pipe.Send(PackMixedRTP(chRTP, p.Pack()));
            //                if (MessageSendRTP != null)
            //                {
            //                    MessageSendRTP(((IPEndPoint)Pipe.RemoteEndPoint).Address.ToString(), ((IPEndPoint)Pipe.RemoteEndPoint).Port, "TCP", chRTP, p);
            //                }
            //            }
            //            _buffer0.Pop();

            //        }
            //        if (!_buffer1.IsEmpty && Pipe.Connected)
            //        {
            //            //先发送SR
            //            RTCPSenderPackage rr1 = new RTCPSenderPackage();
            //            rr1.SendTime = DateTime.UtcNow;
            //            rr1.Timestamp = _buffer1.Packages[0].Timestamp;
            //            rr1.Identifier = _buffer1.Packages[0].SSRC;
            //            //rr1.PacketCount = (uint)_buffer1.Packages.Count(x => x != null);
            //            //rr1.PayloadLength = (uint)_buffer1.Packages.Where(x => x != null).Sum(x => x.Length);
            //            byte chRTCP = 2 + 1;
            //            byte chRTP = 2;
            //            Pipe.Send(PackMixedRTP(chRTCP, rr1.Pack()));
            //            //if (MessageSendRTCP != null)
            //            //{
            //            //    MessageSendRTCP(((IPEndPoint)Pipe.RemoteEndPoint).Address.ToString(), ((IPEndPoint)Pipe.RemoteEndPoint).Port, "TCP", chRTCP, rr1);
            //            //}
            //            foreach (var p in _buffer1.Packages)
            //            {
            //                Pipe.Send(PackMixedRTP(chRTP, p.Pack()));
            //                //if (MessageSendRTP != null)
            //                //{
            //                //    MessageSendRTP(((IPEndPoint)Pipe.RemoteEndPoint).Address.ToString(), ((IPEndPoint)Pipe.RemoteEndPoint).Port, "TCP", chRTP, p);
            //                //}
            //            }
            //            _buffer1.Pop();
            //        }
            //    }
            //}catch(Exception ex)
            //{
            //    int a = 1;
            //}
            //finally
            //{
            //    _timer.Change(0, sendInterval);
            //}
        }

        public bool Pause()
        {
            State = SessionState.Pause;
            _timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
            return false;
        }

        private byte[] PackMixedRTP(byte channel, byte[] data)
        {
            byte[] arr = new byte[1 + 1 + 2 + data.Length];
            arr[0] = 0x24;
            arr[1] = channel;
            Array.Copy(((ushort)data.Length).ToBigEndian(), 0, arr, 2, 2);
            Array.Copy(data, 0, arr, 4, data.Length);
            return arr;
        }

        public void ClearBuffer()
        {
            _buffer0.Reset();
            _buffer1.Reset();
        }
    }
    /// <summary>
    /// 通讯传输协商
    /// </summary>
    public class TransportInfo
    {
        /// <summary>
        /// 流地址
        /// </summary>
        public string StreamId { get; set; }
        /// <summary>
        /// 客户机地址
        /// </summary>
        public string ClientAddress { get; set; }
        /// <summary>
        /// 服务器地址
        /// </summary>
        public string ServerAddress { get; set; }
        /// <summary>
        /// 客户端端口对
        /// </summary>
        public int ClientPort { get; set; }
        /// <summary>
        /// 服务端端口对
        /// </summary>
        public int[] ServerPort { get; set; }
        /// <summary>
        /// 交错层数
        /// </summary>
        public int Interleaved { get; set; }
        /// <summary>
        /// 是否第一个通讯信道
        /// </summary>
        public bool IsFirst { get; set; }
    }

    public enum SessionState
    {
        Init=0,
        Ready=1,
        Play=2,
        Pause=3,
        Close=4
    }
}
